渲染(Render)vs 渲染器(Renderer)
- 渲染(Render):动词,将 vnode 渲染为真实 DOM 的过程
- 渲染器(Renderer):名词,执行渲染工作的核心模块
- 挂载(Mount):将虚拟 DOM 首次渲染到真实 DOM 的过程
Vue 组件中的 mounted 生命周期钩子在 DOM 节点挂载完成后触发。
最简单的渲染器
function render(domString, container) {
container.innerHTML = domString
}
// 使用
render('<div>Hello World</div>', document.body)
javascript
createRenderer 架构
Vue 3 的渲染器通过 createRenderer 函数创建,核心结构:
function createRenderer(options) {
// 从 options 解构平台相关操作
const { createElement, setElementText, insert } = options
function render(vnode, container) {
if (vnode) {
// 有新 vnode:创建或更新
patch(container._vnode, vnode, container)
} else if (container._vnode) {
// 无新 vnode 但有旧 vnode:卸载
unmount(container._vnode)
}
container._vnode = vnode // 记录旧 vnode
}
function patch(n1, n2, container) {
if (!n1) {
mountElement(n2, container) // 挂载
} else {
// 更新(后续涉及 Diff 算法)
patchElement(n1, n2)
}
}
function mountElement(vnode, container) {
const el = createElement(vnode.type)
if (typeof vnode.children === 'string') {
setElementText(el, vnode.children)
} else if (Array.isArray(vnode.children)) {
vnode.children.forEach(child => {
mountElement(child, el)
})
}
insert(el, container)
}
return { render }
}
javascript
自定义渲染器:控制反转
渲染器的核心设计思想是控制反转——将平台相关的 DOM 操作通过 options 注入,使渲染器逻辑可以跨平台复用:
// 浏览器环境
const browserRenderer = createRenderer({
createElement(tag) {
return document.createElement(tag)
},
setElementText(el, text) {
el.textContent = text
},
insert(el, parent, anchor) {
parent.insertBefore(el, anchor)
}
})
// Canvas 环境(理论上)
const canvasRenderer = createRenderer({
createElement(tag) { /* 创建 Canvas 元素 */ },
setElementText(el, text) { /* 绘制文本 */ },
insert(el, parent) { /* 添加到画布 */ }
})
javascript
这种设计使得 Vue 的渲染器核心逻辑(如 patch、mount、Diff)不仅可以在浏览器中使用,也可以在 Node.js(SSR)或其他平台中使用。
核心函数速查
| 函数名 | 源码对应 | 职责 |
|---|---|---|
createRenderer | createRenderer | 创建渲染器实例 |
render | render | 入口,判断挂载/更新/卸载 |
patch | patch | 比对新旧 vnode,分发处理 |
mountElement | mountElement | 首次挂载 vnode 到 DOM |
unmount | unmount | 卸载 vnode 对应的 DOM |
↑